<?php


namespace App\Helpers;


use App\Http\Controllers\Plugin\Models\Java\PdIntegral;
use App\Http\Controllers\Plugin\Models\Java\PdInteLog;
use App\Models\Map\Mch;
use App\Models\Map\ShopGoods;
use App\Models\Map\ShopOrder;
use App\Models\Mch\CapitalFlow;
use App\Models\Mch\OrderRefundLog;
use App\Models\Order\OrderFlow;
use App\Models\Shop\SubMerchant;
use App\Models\User;
use EasyWeChat\Pay\Application;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Transformer;
use WeChatPay\Util\PemUtil;

trait PayTrait
{
    public static $platformCertificateSerial, $platformCertificateFilePath, $merchantPrivateKeyInstance;

    /**
     * @return \WeChatPay\BuilderChainable
     * 合作伙伴
     */
    public static function instance()
    {
        $merchantId = env('TRANSACTION_MCH_ID', '');
// 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        // storage_path(env('TRANSACTION_MchSecretCert',''))
        $merchantPrivateKeyFilePath = 'file://'.storage_path(env('TRANSACTION_MchSecretCert', ''));// 'file:///path/to/merchant/apiclient_key.pem';
//        return $merchantPrivateKeyFilePath;

        self::$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
// 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = env('CERTIFICATESERIAL', '');
// 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        // storage_path(env('TRANSACTION_MchPublicCertPath',''))
        self::$platformCertificateFilePath = 'file://'.storage_path(env('TRANSACTION_PUBLIC_KEY_INSTANCE', ''));//'file:///path/to/wechatpay/cert.pem';
        $platformPublicKeyInstance = self::getPublicKey(self::$platformCertificateFilePath);
// 从「微信支付平台证书」中获取「证书序列号」
        self::$platformCertificateSerial = PemUtil::parseCertificateSerialNo(self::$platformCertificateFilePath);

// 构造一个 APIv3 客户端实例
        return Builder::factory([
            'mchid' => $merchantId,
            'serial' => $merchantCertificateSerial,
            'privateKey' => self::$merchantPrivateKeyInstance,
            'certs' => [
                self::$platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);

    }

    protected static function getPublicKey($platformCertificateFilePath)
    {
        return Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
    }

    public function WechatPay()
    {
        // 工厂方法构造一个实例
        return Builder::factory([
            'mchid' => '1360489602',
            'serial' => 'nop',
            'privateKey' => 'any',
            'certs' => ['any' => null],
            'secret' => '69f1f027b1ebb079532e005a8d665aae',
            'merchant' => [
                'cert' => storage_path(env('MchPublicCertPath', '')),
                'key' => storage_path(env('MchSecretCert', '')),
            ],
        ]);
    }

    public function PublicKeyInstance()
    {
        // PLATFORM_PUBLIC_KEY_INSTANCE 'file:///path/to/wechatpay/inWechatpaySerial.pem'
        $platformPublicKeyInstance = Rsa::from(storage_path(env('PLATFORM_PUBLIC_KEY_INSTANCE', '')), Rsa::KEY_TYPE_PUBLIC);
    }

    public static function WxPay()
    {
        $config = [
            'mch_id' => env('WECHAT_PAY_MCH_ID',1360489602),

            // 商户证书
            'private_key' => storage_path(env('MchSecretCert', '')),
            'certificate' => storage_path(env('MchPublicCertPath', '')),

            // v3 API 秘钥
            'secret_key' => env('SCP_PAY_V3_KEY'),

            // v2 API 秘钥
            'v2_secret_key' => '69f1f027b1ebb079532e005a8d665aae',

            // 平台证书：微信支付 APIv3 平台证书，需要使用工具下载
            // 下载工具：https://github.com/wechatpay-apiv3/CertificateDownloader
            'platform_certs' => [
                storage_path('app/cert/wx/cert.pem')
                // 请使用绝对路径
                // '/path/to/wechatpay/cert.pem',
            ],

            /**
             * 接口请求相关配置，超时时间等，具体可用参数请参考：
             * https://github.com/symfony/symfony/blob/5.3/src/Symfony/Contracts/HttpClient/HttpClientInterface.php
             */
            'http' => [
                'throw' => true, // 状态码非 200、300 时是否抛出异常，默认为开启
                'timeout' => 5.0,
                // 'base_uri' => 'https://api.mch.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用，根据不同的模块配置不同的 uri
            ],
        ];

        return new Application($config);
    }

//    代理商应用
    public static function PlatePay()
    {
        $config = [
            'mch_id' => 1360489602,

            // 商户证书
            'private_key' => storage_path(env('MchSecretCert', '')),
            'certificate' => storage_path(env('MchPublicCertPath', '')),

            // v3 API 秘钥
            'secret_key' => env('SCP_PAY_V3_KEY', ''),

            // v2 API 秘钥
            // 'v2_secret_key' => '26db3e15cfedb44abfbb5fe94fxxxxx',

            // 平台证书：微信支付 APIv3 平台证书，需要使用工具下载
            // 下载工具：https://github.com/wechatpay-apiv3/CertificateDownloader
            'platform_certs' => [
                storage_path('app/cert/wx/cert.pem')
                // 请使用绝对路径
                // '/path/to/wechatpay/cert.pem',
            ],

            /**
             * 接口请求相关配置，超时时间等，具体可用参数请参考：
             * https://github.com/symfony/symfony/blob/5.3/src/Symfony/Contracts/HttpClient/HttpClientInterface.php
             */
            'http' => [
                'throw' => true, // 状态码非 200、300 时是否抛出异常，默认为开启
                'timeout' => 5.0,
                // 'base_uri' => 'https://api.mch.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用，根据不同的模块配置不同的 uri
            ],
        ];

        return new Application($config);
    }

    //自定义商户号
    public function outTrade($pay_type)
    {
        $outtradeno = $pay_type.date('YmdHis').mt_rand(1000000, 99999999);

        return $outtradeno;
    }

//    服务商支付
    protected function TransactionPay($out_trade_no, $real_price, $openid, $sub_mchid, $pay_type = '1')
    {
        $app = $this->PlatePay();
        $appid = env('WECHAT_MINI_APP_APPID');
        $payData = [
            "sp_appid" => $appid, // 服务商应用ID
            "sp_mchid" => env('TRANSACTION_MCH_ID'), // 服务商户号
            "sub_appid" => $appid, // 子商户应用ID
            "sub_mchid" => $sub_mchid, // 子商户号
            "description" => '爱习服务商支付', // 商品描述
            'out_trade_no' => $out_trade_no, // 商户订单号
            "notify_url" => env('APP_URL').env('TRANSACTION_WECHAT_NOTIFY_URL'),
            "attach" => $pay_type, // 支付原样返回
            "amount" => [
                "total" => $real_price,
                "currency" => "CNY"
            ],
            "payer" => [
                "sp_openid" => $openid // <---- 请修改为服务号下单用户的 openid
            ]
        ];
        $response = $app->getClient()->postJson("v3/pay/partner/transactions/jsapi", $payData);

        $prepayId = $response->toArray(false);
        $utils = $app->getUtils();
//        $appId = $appid; // '商户申请的小程序对应的appid，由微信支付生成，可在小程序后台查看';
        $signType = 'RSA'; // 默认RSA，v2要传MD5
        if (isset($prepayId['prepay_id'])) {
            $config = $utils->buildMiniAppConfig($prepayId['prepay_id'], $appid, $signType); // 返回数组

            return $config;
        }else {
            info('微信服务商支付错误', $prepayId);

            return null;
        }
    }
    protected function toArray($data){
        if(is_array($data)){
            return $data;
        }else{
            return json_decode($data,true);
        }
    }
    //    服务商合单支付
    protected function CombineServicePay($request,$sub_order)
    {
        $appid = env('WECHAT_MINI_APP_APPID', '');
        $payData = [
            "combine_appid" => $appid, // 合单商户appid
            'combine_out_trade_no' => $request->out_trade_no, // 合单商户订单号
            "combine_mchid" => env('TRANSACTION_MCH_ID', ''), // 合单商户号
            // 支付者
            'combine_payer_info' => [
                'openid' => $request->openid // 用户子标识
            ],
            "notify_url" => env('APP_URL').env('COMBINE_NOTIFY_URL'),
            //            子单信息
            'sub_orders' => $sub_order,
        ];
        info('准备提交材料',$payData);
        return $this->RequestUrl($payData,'v3/combine-transactions/jsapi');
    }
    protected function getSubOrder($request,$data){
        $arr = [];
        $sp_mchid = env('TRANSACTION_MCH_ID', '');
        foreach ($data as $k=>$item){
            $mch = Mch::query()->select('sub_mchid','pay_type')->where('id',$item['mch_id'])->first();
            $order = OrderFlow::query()
                ->where('out_trade_no',$item['out_trade_no'])
                ->first();

            if(!$order){
                // 如果是活动订单
                if($item['goods_type']==1){
                    $active_order = $this->createActiveOrder($item,$request,$mch);
                    info('如果是活动则创建活动订单'.json_encode($active_order));
                }
                // 创建订单
//                $order = $this->create($request,$goods,$out_trade_no,$goods_type);
                $map = [
                    'order_sn'=>$request->order_sn,
                    'sub_mchid'=>$mch->sub_mchid,
                    'commission_rate'=>$item['rate'],
                    'out_trade_no'=>$item['out_trade_no'],
                    'real_price'=>$item['real_price'],
                    'mch_id'=>$item['mch_id'],
                    'goods_id'=>$item['goods_id'],
                    'goods_type'=>isset($item['goods_type'])?$item['goods_type']:2,
                    'pay_type'=>3,
                    'over_time'=>now()->addMinutes(30),
                    'openid'=>$request->openid,
                    'commission_price'=>$item['real_price']*$item['rate']
                ];
                $order = OrderFlow::query()->create($map);
            }
            // 添加商户流水

            $arr[$k]['mchid'] = $sp_mchid; // 子单发起方商户号，与发起方Appid有绑定关系
            $arr[$k]['attach'] = $item['attach'];
            $arr[$k]['amount'] = [
                'total_amount'=>number_format($item['real_price'],2)*100,
                'currency'=>"CNY",
            ];
            $arr[$k]['out_trade_no'] = $item['out_trade_no'];
            $arr[$k]['sub_mchid'] = $mch->sub_mchid; // 特约商户商户号
            $arr[$k]['description'] = $item['description'];
            if($item['profit_sharing']){
                $arr[$k]['settle_info'] = [
                    'profit_sharing'=>true
                ];
            }
        }
        return $arr;
    }

    /**
     * @param $request
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|mixed
     * 创建活动订单
     */
    protected function createActiveOrder($item,$request,$mch){
        $goods = ShopGoods::query()->find($item['goods_id']);
        if(!$goods){
            return $this->failed('未找到当前商品',201);
        }
        // 限量减库存
        if($goods->is_purchase==1){
            $goods->quantity = $goods->quantity-$request->quantity;
            $goods->save();
        }
//        $mark = $request->input('mark','');
        $order_sn = $item['out_trade_no']; //Str::orderedUuid();
        $ercode = Crypt::encryptString($order_sn);
        // 获取下单用户
        $user = User::query()->where('openid',$request->openid)->first();
        $orderData = [
            'sub_mchid'=>$mch->sub_mchid,
            'er_code'=> $ercode,
            'mch_id' => $goods->mch_id,
            'order_sn'=>$order_sn,
            'nick_name'=>$request->user_name??'',
            'goods_id'=>$goods->id,
            'openid'=>$request->openid,
            'out_trade_no'=>$item['out_trade_no'],
            'price'=>$goods->sale_price,
            'real_price'=>$item['real_price'],
            'phone'=>$request->phone??$user->wx_phone,
            'quantity'=>$item['quantity'],
            'pay_type'=>$mch->pay_type,
            'commission_rate'=>$goods->commission_rate,
            'expire_at'=>$goods->expire_day?now()->addDays($goods->expire_day):null
        ];
        if($request->filled('temp_openid')){
            $orderData['temp_openid'] = $request->temp_openid;
        }
        $order =  ShopOrder::query()->create($orderData);
        if($order){
            $goodsData = [
                'order_id'=>$order->id,
                'category_id'=>$goods->category_id,
                'title'=>$goods->title,
                'sale_price'=>$goods->sale_price,
                'quantity'=>$order->quantity,
                'images'=>$goods->cover,
                'max_person_number'=>$goods->max_person_number,
                'class_time'=>$goods->class_time,
                'min_person_number'=>$goods->min_person_number,
                'last_sale_time'=>$goods->last_sale_time,
            ];
            DB::table('shop_order_goods')->insert($goodsData);
        }
        return $order;
    }
    /**
     * @param $order 订单
     * @param $money 收入或支出金额
     * @param $model 订单模型
     * @return void
     */
    protected function setMchBanlance($order,$type=1){
        $price = 0;
        $model = CapitalFlow::query()->where('mch_id',$order->mch_id)
            ->orderByDesc('id')->first();
        if($model){
            $price = $model->balance;
        }
        $commission_price = $order->real_price*$order->rate;
        if($type==1){
            $balance = $price+$order->real_price-$commission_price;
        }else{
            $balance = $price-$order->real_price;
        }
        $data = [
            'mch_id'=>$order->mch_id,
            'has_model'=>'App\Models\Mch\CapitalFlow',
            'order_sn'=>$order->order_sn,
            'transaction_id'=>$order->transaction_id,
            'out_trade_no'=>$order->out_trade_no,
            'money'=>$type==1?$order->real_price:-$order->real_price,
            'balance'=>$balance,
            'commission_rate'=>$type==1?$order->commission_rate:0.00,
            'commission_price'=>$type==1?$commission_price:0.00,
            'type'=>$type,
            'business_type'=>$type,
            'status'=>$order->status,
            'pay_type'=>$order->pay_type,
        ];
        info('准备提交资金流水',$data);
        $res = CapitalFlow::query()->create($data);
        info('提交流水结果'.json_encode($res));
    }
    protected function refund($order,$money=null)
    {
        $app = $this->WxPay();
        $real_price = $money?$money:$order->real_price;
        $payData = [
            "out_refund_no" => 'rufund'.Str::random(13),
            "out_trade_no" => $order->out_trade_no,
            'reason' => '选错/不想买/买错了',
            'amount' => [
                'refund' => (int)($real_price * 100),
                'total' => (int)($order->real_price * 100),
                'currency' => 'CNY'
            ]

        ];
        $response = $app->getClient()->postJson("v3/refund/domestic/refunds", $payData);

        $result = $response->toArray(false);
        info('获取退款返回结果'.json_encode($result));
        $data = [
            'order_sn' => $order->order_sn,
            'refund_id' => $result['refund_id'],
            'out_refund_no' => $result['out_refund_no'],
            'transaction_id' => $result['transaction_id'],
            'out_trade_no' => $result['out_trade_no'],
            'channel' => $result['channel'],
            'user_received_account' => $result['user_received_account'],
            'success_time' => $result['create_time'],
            'create_time' => $result['create_time'],
            'status' => $result['status'],
            'funds_account' => $result['funds_account'],
            'amount' => json_encode($result['amount']),
            'pay_type' => $order->pay_type,
        ];
        OrderRefundLog::query()->create($data);

        return $result;
    }

//    小程序支付
    protected function miniPay($out_trade_no, $real_price, $oenid,$attach=1)
    {
        $price = intval(strval($real_price));
        // $request->out_trade_no,$request->real_price,$request->openid
        $app = $this->WxPay();
        $appid = env('WECHAT_MINI_APP_APPID');
        $payData = [
            "mchid" => env('WECHAT_PAY_MCH_ID'), // <---- 请修改为您的商户号
            "out_trade_no" => $out_trade_no,
            "appid" => $appid, // <---- 请修改为服务号的 appid
            "description" => '爱习支付',
            "notify_url" => env('APP_URL').env('WECHAT_NOTIFY_URL'),
            'attach' => (string)$attach,
            "amount" => [
                "total" =>$price,
                "currency" => "CNY"
            ],
            "payer" => [
                "openid" => $oenid // <---- 请修改为服务号下单用户的 openid
            ]
        ];
        info('准备提交的资料',$payData);
        $response = $app->getClient()->postJson("v3/pay/transactions/jsapi", $payData);

        $prepayId = $response->toArray(false);
        $utils = $app->getUtils();
//        $appId = $appid; // '商户申请的小程序对应的appid，由微信支付生成，可在小程序后台查看';
        $signType = 'RSA'; // 默认RSA，v2要传MD5
        if (isset($prepayId['prepay_id'])) {
            $config = $utils->buildMiniAppConfig($prepayId['prepay_id'], $appid, $signType); // 返回数组

            return $config;
        }else {
            info('微信支付错误', $prepayId);

            return null;
//            return $this->failed('获取凭证失败',201);
        }
    }
    //小程序退款
    // 查询是否有下过单
    public function getOrder($openid, $goods_id,$goods_type)
    {
        $is_order = ShopOrder::query()
            ->where('openid', $openid)
            ->where('goods_id', $goods_id)
            ->where('goods_type', $goods_type)
            ->where('status', 0)->first();

        return $is_order;

    }

    // 查找商家商户号
    protected function getMchId($mch_id)
    {
        return Mch::query()->select('pay_type', 'sub_mchid','title')->find($mch_id);
    }


    //    服务商分账
    protected function profitsharing($out_trade_no, $real_price, $oenid, $sub_mchid)
    {
        $app = $this->PlatePay();
        $appid = env('WECHAT_MINI_APP_APPID');
        $payData = [
            "sub_mchid" => $appid, // 微信支付分配的子商户号，即分账的出资商户号
            "appid" => $appid, // 微信分配的服务商appid
//            'sub_appid'=> $out_trade_no.$sub_mchid, // 微信分配的子商户公众账号ID，分账接收方类型包含PERSONAL_SUB_OPENID时必填
            'transaction_id' => '', // 微信支付订单号
            'out_order_no' => '',// 服务商系统内部的分账单号
//            分账接收方列表
            'receivers' => [
                'type' => 1, //1、MERCHANT_ID：商户号 2、PERSONAL_OPENID：个人openid（由父商户APPID转换得到） 3、PERSONAL_SUB_OPENID: 个人sub_openid（由子商户APPID转换得到）
                'account' => '', // 分账接收方类型为MERCHANT_ID时，分账接收方账号为商户号
                'amount' => '', // 分账金额，单位为分，只能为整数，不能超过原订单支付金额及最大分账比例金额
                'description' => '财务分账',
            ],

            "unfreeze_unsplit" => true, // 如果为true，该笔订单剩余未分账的金额会解冻回分账方商户
        ];
        $response = $app->getClient()->postJson("v3/profitsharing/orders", $payData);
        $body = $response->body();

        return $this->success($body);
    }

    // 查询分账
    protected function profitsharingCheck($order)
    {
        $app = $this->PlatePay();
        $out_order_no = $order->out_order_no;
        $response = $app->getClient()->get("v3/profitsharing/orders/".$out_order_no);
        $body = $response->body();

        return $this->success($body);
    }

    protected function BankCardPay($out_trade_no, $amount, $enc_bank_no, $enc_true_name, $bank_code)
    {
        $instance = $this->WechatPay();
        $rsaPubKeyString = $this->RsaPublic($instance);
        $rsaPublicKeyInstance = Rsa::from($rsaPubKeyString, Rsa::KEY_TYPE_PUBLIC);
        $encryptor = static function (string $msg) use ($rsaPublicKeyInstance): string {
            return Rsa::encrypt($msg, $rsaPublicKeyInstance);
        };
        $money = $amount * 100;
        $data = [
            'mch_id' => '1360489602',
            'partner_trade_no' => (string)$out_trade_no,
            'enc_bank_no' => (string)$encryptor($enc_bank_no),
            'enc_true_name' => (string)$encryptor($enc_true_name),
            'bank_code' => (string)$bank_code,
            'amount' => (int)$money,
            'desc' => '银行卡支付',
        ];
        $res = $instance
            ->v2->mmpaysptrans->pay_bank
            ->postAsync([
                'xml' => $data,
                'security' => true, //请求需要双向证书
//                'debug' => true,
            ])
            ->then(static function ($response) {
                return $response;

                return Transformer::toArray((string)$response->getBody());
            })
            ->otherwise(static function ($e) {

                return Transformer::toArray((string)$e->getBody());
            })
            ->wait();

        return $res;
    }

    protected function CheckQueryBank($partner_trade_no)
    {
        $instance = $this->WechatPay();

        $data = [
            'mch_id' => env('WECHAT_PAY_MCH_ID','1360489602'),
            'partner_trade_no' => (string)$partner_trade_no,
        ];
        $res = $instance
            ->v2->mmpaysptrans->query_bank
            ->postAsync([
                'xml' => $data,
                'security' => true, //请求需要双向证书
//                'debug' => true,
            ])
            ->then(static function ($response) {
                return $response;

                return Transformer::toArray((string)$response->getBody());
            })
            ->otherwise(static function ($e) {

                return Transformer::toArray((string)$e->getBody());
            })
            ->wait();

        return $res;
    }

    // 获取加密公钥
    public function RsaPublic($instance): string
    {
//        $instance = $this->WechatPay();
        $res = $instance
            ->v2->risk->getpublickey
            ->postAsync([
                'xml' => [
                    'mch_id' => env('WECHAT_PAY_MCH_ID','1360489602'),
                    'sign_type' => 'MD5',
                ],
                'security' => true, //请求需要双向证书
                // 特殊接入点，仅对本次请求有效
                'base_uri' => 'https://fraud.mch.weixin.qq.com/',
            ])
            ->then(static function ($response) {
                return Transformer::toArray((string)$response->getBody());
            })
            ->wait();

        return $res['pub_key'];

    }

    // 合作伙伴调用微信小程序支付
    public function ScpMiniPay($subMch, $order, $request,$attach=1)
    {
        $real_price = $order->real_price * 100;
        if ($real_price <= 0) {
            $real_price = 1;
        }
        $data = [
            'sp_appid' => env('WECHAT_MINI_APP_APPID', ''),// 服务商appid
            'sp_mchid' => env('TRANSACTION_MCH_ID', ''),// 服务商商户id
            'sub_mchid' => $subMch->sub_mchid, // 子商户号
            'description' => $order->order_sn, // 商品描述
            'out_trade_no' => $order->out_trade_no, // 商户订单号
            'attach' => (string)$attach,
            'notify_url' => env('APP_URL').env('SCP_NOTIFY_URL', ''),// 支付回调
            'settle_info' => [
                'profit_sharing' => true,
            ], // 是否指定分账 枚举值:true：是 false：否
            'amount' => [
                "total" => $real_price,
                "currency" => "CNY"
            ], // 支付金额
            'payer' => [
                'sp_openid' => $order->openid
            ],
            'scene_info' => [
                'payer_client_ip' => $request->ip()
            ]
        ];
        return $this->RequestUrl($data,'v3/pay/partner/transactions/jsapi');

    }
    protected function RequestUrl($data,$url){
        $str = 'WECHATPAY2-SHA256-RSA2048 ';
        $timeStamp = (string)Formatter::timestamp();
        $nonceStr = Formatter::nonce();
        $mchid = env('TRANSACTION_MCH_ID');
        $serial_no = env('CERTIFICATESERIAL');
        $auth = [
            'mchid' => $mchid,
            'serial_no' => $serial_no,
            'timeStamp' => $timeStamp,
            'nonceStr' => $nonceStr,
        ];
        $params = $this->makeSign($auth);
        $auth['signature'] = $params['paySign'];
        foreach ($auth as $k => $v) {
            $str .= $k.'="'.$v.'",';
        }
        $newStr = rtrim($str, ',');
        $headers = [
            'Accept' => 'application/json',
            'Content-Type' => 'application/json',
            'Authorization' => $newStr, // 生成认证信息
        ];
        $instance = $this->instance();
        // 开启debug
//        $instance->chain('v3/certificates')->get(
//            ['debug' => true] // 调试模式，https://docs.guzzlephp.org/en/stable/request-options.html#debug
//        );
        try{
            $resp = $instance
                ->chain($url)
                ->post([
                    'json' => $data,
                    'headers' => $headers
                ]);
            $result = json_decode($resp->getBody());
            if ($result->prepay_id) {
                $params = [
                    'appId' => env('WECHAT_MINI_APP_APPID'),
                    'timeStamp' => (string)Formatter::timestamp(),
                    'nonceStr' => Formatter::nonce(),
                    'package' => 'prepay_id='.$result->prepay_id,
                ];
                $params = $this->makeSign($params);
            }

            return $params;
        }catch (\Exception $e){
            // 进行错误处理
            echo '运行错误';
            echo $e->getMessage(), PHP_EOL;
            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {

                $r = $e->getResponse();
                echo $r->getStatusCode().' '.$r->getReasonPhrase(), PHP_EOL;
                echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
                info('合单支付报错'.$r->getStatusCode().'_'.json_encode($r->getBody()));
            }
            echo $e->getTraceAsString(), PHP_EOL;

            return $this->failed('请求失败');
        }
    }

    public function makeSign($params)
    {
        $merchantPrivateKeyFilePath = 'file://'.storage_path(env('TRANSACTION_MchSecretCert', ''));
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        $params += [
            'paySign' => Rsa::sign(
                Formatter::joinedByLineFeed(...array_values($params)),
                $merchantPrivateKeyInstance
            ),
            'signType' => 'RSA'
        ];

        return $params;
    }
    // 设置签名
    protected function signature($url,$request,$nonce,$timestamp){
        $merchantPrivateKeyFilePath = 'file://'.storage_path(env('TRANSACTION_MchSecretCert', ''));
        $privateKey = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        $parames = Formatter::request(
            'POST', $url, $timestamp, $nonce, json_encode($request)
        );
        $signature = Rsa::sign($parames, $privateKey);
        return $signature;
    }

    // 组合分账
    protected function setSignData()
    {
        $auth = [
            'mchid' => env('WECHAT_PAY_MCH_ID'),
            'serial_no' => env('CERTIFICATESERIAL'),
            'timeStamp' => (string)Formatter::timestamp(),
            'nonceStr' => Formatter::nonce(),
        ];
        $params = $this->makeSign($auth);
        $auth['signature'] = $params['paySign'];
        $str = 'WECHATPAY2-SHA256-RSA2048 ';
        foreach ($auth as $k => $v) {
            $str .= $k.'="'.$v.'",';
        }
        $newStr = rtrim($str, ',');

        $header = [
            'accept' => 'application/json',
            'content-type' => 'application/json',
            'authorization' => $newStr, // 生成认证信息
        ];

        return $header;
    }

    //公共组件
    protected function devideAccountCommon($data, $url, $serial = null)
    {
        $header = $this->setSignData();
        if ($data) {
            info('请求微信发送参数', $data);
        }

        // paySign
        $instance = $this->instance();
//        $resp = $instance->chain('v3/certificates')->get(
//            ['debug' => true] // 调试模式，https://docs.guzzlephp.org/en/stable/request-options.html#debug
//        );
        if ($serial) {
            $header['Wechatpay-Serial'] = self::$platformCertificateSerial;
        }
        try{
            if ($data) {
                $resp = $instance
                    ->chain($url)
                    ->post([
                        'json' => $data,
                        'headers' => $header
                    ]);
            }else {
                $resp = $instance
                    ->chain($url)
                    ->get([
                        'headers' => $header
                    ]);
            }
            $result = json_decode($resp->getBody());
            info('微信返回参数'.json_encode($result));
            if (is_object($result)) {
                info('获取对象');
            }else {
                if (is_array($result)) {
                    info('获取到的数组');
                }
            }

            return $result;
        }catch (\Exception $e){
            // 进行错误处理
            echo '运行错误';
            echo $e->getMessage(), PHP_EOL;
            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                $r = $e->getResponse();
                echo $r->getStatusCode().' '.$r->getReasonPhrase(), PHP_EOL;
                echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
            }
            echo $e->getTraceAsString(), PHP_EOL;

            return $this->failed('请求失败');
        }
    }

    protected function changeOrderRefund($order)
    {
        $order->status = -1;
        $order->save();
        // 变更订单流水状态
        $orderFlow = OrderFlow::query()->where('out_trade_no',$order->out_trade_no)->first();
        if($orderFlow){
            $orderFlow->status = -1;
            $orderFlow->refund_price = $order->real_price;
            $orderFlow->save();
        }
        $this->setMchBanlance($order,2);
    }
    protected function refundFlow($mch_id,$order_sn,$money){
        // 订单流水
        $orderFlow = OrderFlow::query()->where('order_sn',$order_sn)->first();
        $orderFlow->status = -1;
        $orderFlow->refund_price = $money;
        $orderFlow->save();
        $capitalFlow = CapitalFlow::query()->orderByDesc('id')->first();
        $balance = $capitalFlow->balance;
        $capital = [
            'mch_id'=>$mch_id,
            'order_sn'=>$order_sn,
            'money'=>-$money,
            'type'=>2,
            'balance'=>$balance-$money,
        ];
        CapitalFlow::query()->create($capital);
        // 资金流水
    }
    // 变更积分状态
    protected function changeScore($out_trade_no){
        $integralLog = PdInteLog::query()
            ->where('is_reduce',1)
            ->where('inte','>',0)
            ->where('order_id',$out_trade_no)->get();
        if($integralLog){
            foreach ($integralLog as $item){
                $item->status = 2; // 退款
                $item->save();
            }

        }
    }
    // 退还积分
    protected function returnScore($out_trade_no){
        $integralLog = PdInteLog::query()
            ->where('is_reduce',1)
            ->where('inte','>',0)
            ->where('order_id',$out_trade_no)->get();
        if($integralLog){
            foreach ($integralLog as $item){
                PdIntegral::query()
                    ->where('uid',$item->uid)
                    ->decrement('fake_inte',$item->inte);
                $item->status = 2; // 退款
                $item->save();
            }

        }
    }
}
